﻿// Inner Fire 游戏引擎库
// LuaManager - LUA管理器
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 用于Lua的管理器
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-03-26

#include "lua_manager.h"
#include <game/animation/animator.h>
#include <game/manager/game_manager.h>
#include <game/manager/scene.h>
#include <game/resource/assets.h>
#include <global_switch.h>

namespace ifire::game {

static LuaManager* manager;
const char* NIL_TEXT = "nil";

static int lua_print_debug(lua_State* L) {
  static char buffer[1024];
  lua_sprintf(L, buffer, 1024);
  manager->PrintDebug(0, buffer, 0);
  return 0;
}

/// <summary>
/// 这里有一个非常奇怪的BUG，这个构造函数只能在文件的这个地方。
/// 如果我把这个函数放在前面（比如文件的开头），就会发生内存崩溃的BUG。
/// 应该和一些static的东西有关。现在暂时放在文件的这个位置，不会发生问题
/// </summary>
LuaManager::LuaManager(GameManager* gm)
    : gm_(gm)
    , lua_env_(new ikit::LuaEnv())
    , ls_(lua_env_->GetState())
    , init_func_("lua_init")
    , fixed_update_func_("on_fixed_update")
    , key_down_func("on_key_down")
    , key_up_func("on_key_up")
    , char_func("on_char") {
  manager = this;
}

LuaManager::~LuaManager() { delete lua_env_; }

void LuaManager::OnLoaded() {
  // 注册常用指令
  RegisterGlobalFunction();

  // 注册函数
  lua_register(ls_, "print_debug", lua_print_debug);

  // 注册每个模块的相关元表
  register_lua_animator(ls_, this);
  register_lua_objects(ls_, this);
  register_lua_physics(ls_, this);
  register_lua_graphics(ls_, this);
  register_lua_assets(ls_, this);
  register_lua_game_manager(ls_, this);
  register_lua_ui(ls_, this);
  register_lua_controller(ls_, this);

  // 运行初始化Lua代码
  if (lua_env_->Run(gm_->CurrentScene()->GetLuaScript().c_str())) {
    lua_env_->Call(init_func_);
  }
}

void LuaManager::OnFixedUpdate() { lua_env_->Call(fixed_update_func_); }

void LuaManager::RegisterGlobalFunction() {
  ikit::register_gfunction("Exit", [](int pid, float pvalue) -> float {
    exit(0);
    return 0.0f;
  });
  ikit::register_gfunction("SwitchWireMode",
      [this](int, float) -> float { return this->SwitchWireMode(); });
  ikit::register_gfunction("SwitchCameraMode",
      [this](int, float) -> float { return this->SwitchCameraMode(); });
  ikit::register_gfunction("SetCameraMode",
      [this](int pid, float) -> float { return this->SetCameraMode(pid); });
  ikit::register_gfunction("LockCursor",
      [this](int pid, float) -> float { return this->LockCursor(pid); });
  ikit::register_gfunction(
      "SetCameraControlBySystem", [this](int pid, float) -> float {
        return this->SetCameraControlBySystem(pid);
      });
}

void LuaManager::OnKeyDown(int key) { lua_env_->Call_Int(key_down_func, key); }

void LuaManager::OnKeyUp(int key) { lua_env_->Call_Int(key_up_func, key); }

void LuaManager::OnChar(int c) { lua_env_->Call_Int(char_func, c); }

void LuaManager::OnButtonClick(
    ikit::sstr button_id, int int_param, float float_param) {
  const static ikit::sstr button_func("on_button_click");
  lua_env_->Call_Button(button_func, button_id, int_param, float_param);
}

void LuaManager::OnMouseMove(int delta_x, int delta_y) {
  const static ikit::sstr func("on_mouse_move");
  lua_env_->Call_Int2(func, delta_x, delta_y);
}

void LuaManager::OnMouseEvent(int mouse_button, int x, int y, bool is_pressed) {
  const static ikit::sstr func("on_mouse_event");
  int reg_id = lua_env_->Reg(func);
  if (lua_env_->Ready(reg_id)) {
    lua_pushinteger(ls_, (lua_Integer)mouse_button);
    lua_pushinteger(ls_, (lua_Integer)x);
    lua_pushinteger(ls_, (lua_Integer)y);
    lua_pushboolean(ls_, is_pressed ? 1 : 0);
    lua_env_->CallFunc(reg_id, 4, 0);
  }
}

void LuaManager::OnGamepadButton(int button_id, int event_id) {
  const static ikit::sstr func("on_gamepad_button");
  lua_env_->Call_Int2(func, button_id, event_id);
}

void LuaManager::OnLeftStick(float x, float y) {
  const static ikit::sstr left_stick_func("on_left_stick");
  lua_env_->Call_Float2(left_stick_func, x, y);
}

void LuaManager::OnRightStick(float x, float y) {
  const static ikit::sstr right_stick_func("on_right_stick");
  lua_env_->Call_Float2(right_stick_func, x, y);
}

void LuaManager::PrintDebug(int index, const char* text, size_t len) {
  gm_->PrintDebug(index, text, len);
}

float LuaManager::SwitchWireMode() {
  auto dx = gm_->GetGraphics();
  dx->SetWireMode(!dx->IsWireMode());
  return 0.0f;
}

float LuaManager::SwitchCameraMode() {
  auto dx = gm_->GetGraphics();
  if (dx->GetView().GetCameraType() == dx::CameraType::NORMAL) {
    dx->GetView().SetCameraType(dx::CameraType::SPHERICAL);
  } else {
    dx->GetView().SetCameraType(dx::CameraType::NORMAL);
  }
  dx->GetView().ResetCamera();
  return 0.0f;
}

float LuaManager::SetCameraMode(int type) {
  auto dx = gm_->GetGraphics();
  dx->GetView().SetCameraType((dx::CameraType)type);
  dx->GetView().ResetCamera();
  return 0.0f;
}

float LuaManager::LockCursor(bool enable) {
  gm_->GetInput()->SetMouseLock(enable);
  return 0.0f;
}

float LuaManager::SetCameraControlBySystem(bool enable) {
  gm_->GetGraphics()->GetView().SetTakeControl(enable);
  return 0.0f;
}

} // namespace ifire::game